package com.heima.article.job;
import com.alibaba.fastjson.JSON;
import com.heima.article.service.HotArticleService;
import com.heima.model.common.constants.article.HotArticleConstants;
import com.heima.model.mess.app.AggBehaviorDTO;
import com.heima.model.mess.app.NewBehaviorDTO;
import com.xxl.job.core.biz.model.ReturnT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class UpdateHotArticleJob {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    HotArticleService hotArticleService;
    public ReturnT updateHotArticleHandler(String params){
        log.info("热文章分值更新 调度任务开始执行....");
        List<NewBehaviorDTO> newBehaviorList = getRedisBehaviorList();
        if (CollectionUtils.isEmpty(newBehaviorList)){
            log.info("太冷清了 ，最近10s 没人访问我们的文章数据....");
            return ReturnT.SUCCESS;
        }
        List<AggBehaviorDTO> aggBehaviorList = getAggBehaviorList(newBehaviorList);
        if (CollectionUtils.isEmpty(aggBehaviorList)){
            log.info("太冷清了 ，最近10s 没人访问我们的文章数据....");
            return ReturnT.SUCCESS;
        }
        // 定时更新文章热度
        aggBehaviorList.forEach(hotArticleService::updateApArticle);
        log.info("热文章分值更新 调度任务完成....");
        return ReturnT.SUCCESS;
    }

    private List<AggBehaviorDTO> getAggBehaviorList(List<NewBehaviorDTO> newBehaviorList) {
        List<AggBehaviorDTO> aggBehaviorDTOS = new ArrayList<>();
        Map<Long,List<NewBehaviorDTO>> map = newBehaviorList.stream().collect(Collectors.groupingBy(NewBehaviorDTO::getArticleId));
        map.forEach(((getArticleId, newBehaviorDTOS) -> {
            Optional<AggBehaviorDTO> aggResult = newBehaviorDTOS.stream().map(this::parseAggBehavior)
                    .reduce((a1,a2) ->{
                        a1.setLike(a1.getLike()+a2.getLike());
                        a1.setCollect(a1.getCollect()+a2.getCollect());
                        a1.setView(a1.getView()+a1.getView());
                        a1.setComment(a1.getComment()+ a2.getComment());
                        return a1;
                    });
            if (aggResult.isPresent()) {
                aggBehaviorDTOS.add(aggResult.get());
            }
        }));
        return aggBehaviorDTOS;
    }


    private AggBehaviorDTO parseAggBehavior(NewBehaviorDTO behavior){
        AggBehaviorDTO aggBehaviorDTO = new AggBehaviorDTO();
        aggBehaviorDTO.setArticleId(behavior.getArticleId());
        switch (behavior.getType()){
            case VIEWS:
                aggBehaviorDTO.setView(behavior.getAdd());
                break;
            case LIKES:
                aggBehaviorDTO.setLike(behavior.getAdd());
                break;
            case COMMENT:
                aggBehaviorDTO.setComment(behavior.getAdd());
                break;
            case COLLECTION:
                aggBehaviorDTO.setCollect(behavior.getAdd());
                break;
            default:
        }
        return aggBehaviorDTO;
    }
    /**
     * 从redis list拿取数据
     * @return
     */
    private List<NewBehaviorDTO> getRedisBehaviorList() {
        //执行lua脚本
        DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
        //设置脚本返回值
        redisScript.setResultType(List.class);
        //设置脚本
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis.lua")));
        List<String> result = redisTemplate.execute(redisScript, Arrays.asList(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST));
        return result.stream()
                .map(jsonStr -> JSON.parseObject(jsonStr,NewBehaviorDTO.class)).collect(Collectors.toList());
    }
}